/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.web.formmetadata.replication;

import com.inspur.edp.cdp.web.component.metadata.define.WebComponentMetadata;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataDto;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.web.command.component.metadata.CmpMethodRefering;
import com.inspur.edp.web.command.component.metadata.WebCommandsMetadata;
import com.inspur.edp.web.common.customexception.WebCustomException;
import com.inspur.edp.web.common.io.FileUtility;
import com.inspur.edp.web.common.logger.WebLogger;
import com.inspur.edp.web.common.metadata.MetadataGetterParameter;
import com.inspur.edp.web.common.metadata.MetadataTypeEnum;
import com.inspur.edp.web.common.metadata.MetadataUtility;
import com.inspur.edp.web.common.serialize.SerializeUtility;
import com.inspur.edp.web.common.utility.StringUtility;
import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import com.inspur.edp.lcm.metadata.api.entity.MetadataType;

import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Pattern;

/**
 * 命令元数据拷贝
 *
 * @author guozhiqi
 */
public class FormMetadataCmdManager {

    // public static void main(String[] args) {
    //     String formCode = "FORMCODE";
    //     String commandCode = "FORMCODE_frm_Controller.webcmd";
    //     String pattern = "^" + formCode + "_(m)?frm_";
    //     boolean isOwnCommand = false;
    //     if (Pattern.matches(pattern, commandCode)) {
    //         isOwnCommand = true;
    //     }
    //     System.out.println(isOwnCommand);
    // }
    public static void copy(MetadataReplicationContext context, GspMetadata sourceFormMetadata,
                            MetadataDto targetMetadataDescription, FormDOM replicateFormDOM) {
        ArrayList<HashMap<String, Object>> webcmdCollection = replicateFormDOM.getModule().getWebcmds();
        if (webcmdCollection != null && !webcmdCollection.isEmpty()) {
            String formCode = sourceFormMetadata.getHeader().getCode();
            for (HashMap<String, Object> webcmd : webcmdCollection) {
                String webcmdId = webcmd.containsKey("id") ? webcmd.get("id").toString() : "";
                if (StringUtility.isNullOrEmpty(webcmdId)) {
                    WebLogger.Instance.info("表单元数据复制，webcmds节点下，对应的id参数为空。完整的命令信息：" + webcmd);
                    continue;
                }
                MetadataGetterParameter metadataGetterParameter = MetadataGetterParameter.getNewInstance(webcmdId, sourceFormMetadata.getRelativePath(), MetadataTypeEnum.Command);
                metadataGetterParameter.setSourceMetadata(sourceFormMetadata, MetadataTypeEnum.Frm);

                GspMetadata webCmdMetadata = MetadataUtility.getInstance().getMetadataWithDesign(metadataGetterParameter);
                if (webCmdMetadata == null) {
                    throw new WebCustomException("复制表单元数据时，获取命令构件失败。待获取命令构件ID是：" + webcmdId);
                }

                WebCommandsMetadata webCommandMetadataContent = (WebCommandsMetadata) webCmdMetadata.getContent();
                // 复制自定义命令构件及关联服务构件
                if (webCommandMetadataContent != null && webCommandMetadataContent.getExtendProperty() != null &&
                        !webCommandMetadataContent.getExtendProperty().isCommon()) {
                    // bugfix: 542444。非本表单创建的构件不复制
                    boolean isOwnCommand = false;
                    String commandFormCode = webCommandMetadataContent.getExtendProperty().getFormCode();
                    if (commandFormCode != null && commandFormCode.equals(formCode)) {
                        isOwnCommand = true;
                    } else {
                        String commandCode = webCmdMetadata.getHeader().getCode();
                        String pattern = "^" + formCode + "_(m)?frm_";
                        if (Pattern.matches(pattern, commandCode)) {
                            isOwnCommand = true;
                        }
                    }
                    if (!isOwnCommand) {
                        continue;
                    }

                    // 拷贝这个命令构件
                    MetadataDto webCommandMetadataDto = new MetadataDto();
                    // TODO：如何保证正确替换code和name
                    webCommandMetadataDto.setCode(webCmdMetadata.getHeader().getCode().replace(webCommandMetadataContent.getExtendProperty().getFormCode(), targetMetadataDescription.getCode()));
                    String name = webCmdMetadata.getHeader().getName().replace(sourceFormMetadata.getHeader().getName(), targetMetadataDescription.getName());
                    webCommandMetadataDto.setName(name);
                    HashMap<String, String> nameLanguage = new HashMap<>();
                    nameLanguage.put("zh-CHS", name);
                    webCommandMetadataDto.setNameLanguage(nameLanguage);
                    webCommandMetadataDto.setProjectName(targetMetadataDescription.getProjectName());
                    webCommandMetadataDto.setRelativePath(targetMetadataDescription.getRelativePath());
                    webCmdMetadata.setExtendProperty(webCmdMetadata.getExtendProperty().replace(sourceFormMetadata.getHeader().getCode().split(Pattern.quote("_"), -1)[0], targetMetadataDescription.getCode().split(Pattern.quote("_"), -1)[0]));

                    MetadataReplicationContext webCommandMetadataReplicationContext = new MetadataReplicationContext();
                    webCommandMetadataReplicationContext.setSourceProjectName(context.getSourceProjectName());
                    webCommandMetadataReplicationContext.setSourceMetadata(webCmdMetadata);
                    webCommandMetadataReplicationContext.setTargetMetadataDescription(webCommandMetadataDto);

                    GspMetadata replicateWebCommandMetadata = MetadataCloneManager.cloneMetadata(webCommandMetadataReplicationContext);
                    MetadataUtility.getInstance().createMetadataIfNotExistsWithDesign(replicateWebCommandMetadata);

                    // 更新表单内容关联webcmd
                    String oldWebCmdId = webcmd.get("id").toString();
                    webcmd.put("id", replicateWebCommandMetadata.getHeader().getId());
                    webcmd.put("name", replicateWebCommandMetadata.getHeader().getFileName());

                    // 更新ViewModels中关联webcmd
                    String viewModelCollectionStr = SerializeUtility.getInstance().serialize(replicateFormDOM.getModule().getviewmodels(), false);
                    // 将viewModel中 替换webCmd
                    viewModelCollectionStr = viewModelCollectionStr.replace(oldWebCmdId, webcmd.get("id").toString());
                    replicateFormDOM.getModule().setviewmodels(SerializeUtility.getInstance().deserialize(viewModelCollectionStr, ArrayList.class));

                    //统一使用源工程路径查找
                    replicateWebCommandMetadata.setRelativePath(context.getSourceMetadata().getRelativePath());

                    // 查找自定义命令构件中使用的服务构件
                    MetadataUtility.getInstance().getReferenceComponentMetadata(replicateWebCommandMetadata, FormMetadataCmdManager::UpdateWebComponentMetadata, context);

                    // 保存命令元数据
                    MetadataUtility.getInstance().saveMetadataWithDesign(replicateWebCommandMetadata);
                }
            }
        }
    }

    private static void UpdateWebComponentMetadata(GspMetadata commandMetadata, CmpMethodRefering methodReferingItem, GspMetadata componentMetadata, Object... parameterArray) {
        if (parameterArray.length != 1) {
            return;
        }
        MetadataReplicationContext metadataReplicationContext = (MetadataReplicationContext) parameterArray[0];
        GspMetadata sourceFormMetadata = metadataReplicationContext.getSourceMetadata();
        String sourceProjectName = metadataReplicationContext.getSourceProjectName();
        MetadataDto targetMetadataDescription = metadataReplicationContext.getTargetMetadataDescription();

        WebComponentMetadata componentMetadataContent = (WebComponentMetadata) componentMetadata.getContent();
        // 无需拷贝公共服务构件，仅拷贝自定义服务构件
        if (componentMetadataContent.isCommon()) {
            return;
        }

        // 查找指定路径是否存在相同元数据，如果存在使用已有元数据，如果没有则创建一个

        MetadataDto webComponentMetadataDto = new MetadataDto();
        // TODO：如何保证正确替换code和name
        webComponentMetadataDto.setCode(componentMetadata.getHeader().getCode().replace(componentMetadataContent.getFormCode(), targetMetadataDescription.getCode()));
        HashMap<String, String> nameLanguage = new HashMap<>();
        String name = componentMetadata.getHeader().getName().replace(sourceFormMetadata.getHeader().getName(), targetMetadataDescription.getName());
        nameLanguage.put("zh-CHS", name);
        webComponentMetadataDto.setNameLanguage(nameLanguage);
        webComponentMetadataDto.setName(name);
        webComponentMetadataDto.setProjectName(targetMetadataDescription.getProjectName());
        webComponentMetadataDto.setRelativePath(targetMetadataDescription.getRelativePath());


        // TODO：替换方式不准确，待优化
        componentMetadata.setExtendProperty(componentMetadata.getExtendProperty().replace(sourceFormMetadata.getHeader().getCode().split(Pattern.quote("_"), -1)[0],
                targetMetadataDescription.getCode().split(Pattern.quote("_"), -1)[0]));
        MetadataReplicationContext componentMetadataReplicationContext = new MetadataReplicationContext();
        componentMetadataReplicationContext.setSourceMetadata(componentMetadata);
        componentMetadataReplicationContext.setSourceProjectName(metadataReplicationContext.getSourceProjectName());
        componentMetadataReplicationContext.setTargetMetadataDescription(webComponentMetadataDto);

        GspMetadata replicateWebComponentMetadata = MetadataCloneManager.cloneMetadata(componentMetadataReplicationContext);

        // TODO：提取RelativePath赋值操作，这样就无需先clone元数据再执行是否存在校验
        if (!CheckIfMetadataFileExits(replicateWebComponentMetadata)) {
            MetadataUtility.getInstance().createMetadataIfNotExistsWithDesign(replicateWebComponentMetadata);
        } else {
            replicateWebComponentMetadata = MetadataUtility.getInstance().getMetadataWithDesign(replicateWebComponentMetadata.getHeader().getFileName(), replicateWebComponentMetadata.getRelativePath());
        }

        // 更新命令构件关联的服务构件
        methodReferingItem.setComponentId(replicateWebComponentMetadata.getHeader().getId());
        methodReferingItem.setComponentCode(replicateWebComponentMetadata.getHeader().getCode());
        methodReferingItem.setComponentName(replicateWebComponentMetadata.getHeader().getName());
        methodReferingItem.setComponentPath(replicateWebComponentMetadata.getRelativePath());

        componentMetadataContent.setName(commandMetadata.getHeader().getName());


        // 拷贝服务构件关联的文件（.ts文件）
        FormMetadataCmpSourceTsFileCloneManager.copy(componentMetadataContent, sourceProjectName, targetMetadataDescription.getProjectName(), componentMetadata, replicateWebComponentMetadata);

        MetadataUtility.getInstance().saveMetadataWithDesign(replicateWebComponentMetadata);
    }

    private static boolean CheckIfMetadataFileExits(GspMetadata metadata) {
        MetadataUtility metadataUtility = MetadataUtility.getInstance();

        String absolutePath = metadataUtility.getAbsolutePath(metadata.getRelativePath());
        //元数据名称
        String metadataName = GetMetadataFullName(metadata);

        //元数据完整路径
        String fullPath = Paths.get(absolutePath).resolve(metadataName).toString();
        return FileUtility.exists(fullPath);
    }

    private static String GetMetadataFullName(GspMetadata metadata) {
        MetadataService ser = SpringBeanUtils.getBean(MetadataService.class);
        List<MetadataType> metadataTypeList = ser.getMetadataTypeList();
        Optional<MetadataType> first = metadataTypeList.stream().filter((type) -> type.getTypeCode().equals(metadata.getHeader().getType())).findFirst();
        return metadata.getHeader().getCode() + first.get().getPostfix();
    }

}
